package org.springblade.modules.app.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.model.TransferModel;
import com.jpay.ext.kit.IpKit;
import com.jpay.ext.kit.StrKit;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.config.NoRepeatSubmit;
import org.springblade.common.config.WxPayConfig;
import org.springblade.common.utils.DecimalUtil;
import org.springblade.common.utils.MoneyUtil;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.modules.app.entity.MoneyDetail;
import org.springblade.modules.app.entity.TransMoney;
import org.springblade.modules.app.service.IMoneyDetailService;
import org.springblade.modules.app.service.ITransMoneyService;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.IUserService;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

/***
 *  //FIXME kingkong 1827245563@qq.com
 *  //FIXME 资金安全问题 资金安全问题 资金安全问题 资金安全问题 资金安全问题 资金安全问题 资金安全问题
 *  //FIXME   WARNING  WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
 *  //FIXME 1.避免高并发下 恶意提现申请  控制s单位内 并发数 NsumRepeat 问题
 *  //FIXME 2.避免恶意参数注入-1提现问题
 *  //FIXME 3.APi开放的端口 后续 做ak sk 因子校验 证书双端签名和验签
 *  //FIXME 4.提现密码 需要有 业务暂时说不需要  不安全  谨记
 *  //FIXME 5.HTTPS HTTPS HTTPS HTTPS HTTPS HTTPS HTTPS HTTPS 多说无益 这是最基本的
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("blade-app/transmoney")
@Api(value = "提现记录", tags = "提现记录接口")
public class TransMoneyController extends BladeController {

    private final ITransMoneyService transMoneyService;
    private final IUserService userService;
    private final IMoneyDetailService moneyDetailService;


    /**
     * 详情
     */
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "详情", notes = "传入transMoney")
    public R<TransMoney> detail(TransMoney transMoney) {
        TransMoney detail = transMoneyService.getOne(Condition.getQueryWrapper(transMoney));
        return R.data(detail);
    }

    /**
     * 分页 提现记录
     */
    @GetMapping("/list")
    public R<IPage<TransMoney>> list(Page page, TransMoney transMoney) {
        IPage<TransMoney> pages = transMoneyService.page(page, new LambdaQueryWrapper<TransMoney>().eq(TransMoney::getApplystatus, "1").orderByDesc(TransMoney::getCtime));
        return R.data(pages);
    }

    /**
     * 自定义分页 提现记录
     */
    @GetMapping("/page")
    public R<IPage<TransMoney>> page(Page page, TransMoney transMoney) {
        IPage<TransMoney> pages = transMoneyService.page(page, new LambdaQueryWrapper<TransMoney>().eq(TransMoney::getApplystatus, "1"));
        return R.data(pages);
    }


    @GetMapping("/transMoneyLogByUser")
    public R<IPage<TransMoney>> transMoneyLogByUser(Page page, TransMoney transMoney) {
        BladeUser bladeUser = AuthUtil.getUser();
        IPage<TransMoney> pages = transMoneyService.page(page, new LambdaQueryWrapper<TransMoney>().eq(TransMoney::getApplystatus, "2").eq(TransMoney::getSqruserid, bladeUser.getUserId()));
        return R.data(pages);
    }


    ///提现申请
    @NoRepeatSubmit
    @PostMapping("/transMoneyApply")
    public R transMoneyApply(@RequestBody TransMoney transMoney) {
        BladeUser bladeUser = AuthUtil.getUser();
        User userInfo = userService.getById(bladeUser.getUserId());


        //FIXME 防st恶意注入 安全金额参数必须大于等于0
        if (DecimalUtil.defineLessZeroGetTrue(transMoney.getTransmoney())) {
            log.error("资金安全日志: 提现金额为负数/谨防HK尝试恶意注入 提现");
            return R.fail("资金安全日志: 用户账户金额为负数/谨防HK尝试恶意注入 提现");
        }

        //FIXME 防st恶意注入 安全金额参数必须大于等于0
        if (DecimalUtil.defineLessZeroGetTrue(userInfo.getAccountmoney())) {
            log.error("资金安全日志: 用户账户金额为负数/谨防HK尝试恶意注入 提现");
            return R.fail("资金安全日志: 用户账户金额为负数/谨防HK尝试恶意注入 提现");
        }


        int result1 = userInfo.getAccountmoney().compareTo(transMoney.getTransmoney());
        if (result1 == -1) {
            log.error("资金安全日志: 提现金额大于账户余额");
            return R.fail("资金安全日志: 账户余额小于提现金额");
        }


        BigDecimal bigDecimalBy1 = new BigDecimal(1.00);
        int bigDecimalBy1Res = transMoney.getTransmoney().compareTo(bigDecimalBy1);
        if (bigDecimalBy1Res == -1) {
            log.error("资金安全日志: 提现金额小于1");
            return R.fail("资金安全日志: 提现金额不能小于1元");
        }

        BigDecimal bigDecimalBy5000 = new BigDecimal(5000.00);
        int bigDecimalBy5000Res = transMoney.getTransmoney().compareTo(bigDecimalBy5000);
        if (bigDecimalBy5000Res == 1) {
            log.error("资金安全日志: 提现金额不能大于5000");
            return R.fail("资金安全日志: 提现金额不能大于5000");
        }


        TransMoney checkResult = transMoneyService.getOne(new LambdaQueryWrapper<TransMoney>().eq(TransMoney::getSqruserid, userInfo.getId()).eq(TransMoney::getApplystatus, "1"));
        if (!StringUtils.isEmpty(checkResult)) {
            return R.fail("资金安全日志: 有审核中数据请稍后");
        }

        transMoney.setSqruserid(userInfo.getId() + "");
        transMoney.setSqrusername(userInfo.getName());
        transMoney.setSqruserphone(userInfo.getPhone());
        //申请提现金额
        transMoney.setTransmoney(transMoney.getTransmoney());
        transMoney.setWxopenid(userInfo.getWxopenid());
        transMoney.setApplystatus("1");
        transMoney.setApplydate(new Date());
        transMoney.setCtime(new Date());
        return R.status(transMoneyService.save(transMoney));
    }

    /**
     * 驳回
     */
    @PostMapping("/update")
    public R update(@RequestBody TransMoney transMoney) {
        return R.fail("功能未开发");
    }

    /**
     * 新增或修改 提现记录
     */
    @PostMapping("/submit")
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "新增或修改", notes = "传入transMoney")
    public R submit(@Valid @RequestBody TransMoney transMoney) {
        return R.fail("功能未开发");
    }


    /**
     * 同意提现
     */
    @NoRepeatSubmit
    @PostMapping("/transMoneyAccept")
    public R transMoneyAccept(@RequestParam String ids) {

        BladeUser bladeUser = AuthUtil.getUser();
        User adminUserInfo = userService.getById(bladeUser.getUserId());

        TransMoney transMoneyInfo = transMoneyService.getById(ids);

        //FIXME 防st恶意注入 安全金额参数必须大于等于0
        if (DecimalUtil.defineLessZeroGetTrue(transMoneyInfo.getTransmoney())) {
            log.error("资金安全日志: 提现金额为负数/尝试恶意注入 提现");
            return R.fail("资金安全日志: 提现金额为负数/尝试恶意注入 提现");
        }


        User workUserInfo = userService.getById(transMoneyInfo.getSqruserid());


        //FIXME 防st恶意注入 安全金额参数必须大于等于0
        if (DecimalUtil.defineLessZeroGetTrue(transMoneyInfo.getTransmoney())) {
            log.error("资金安全日志: 提现金额为负数/谨防HK尝试恶意注入 提现");
            return R.fail("资金安全日志: 用户账户金额为负数/谨防HK尝试恶意注入 提现");
        }

        //FIXME 防st恶意注入 安全金额参数必须大于等于0
        if (DecimalUtil.defineLessZeroGetTrue(workUserInfo.getAccountmoney())) {
            log.error("资金安全日志: 用户账户金额为负数/谨防HK尝试恶意注入 提现");
            return R.fail("资金安全日志: 用户账户金额为负数/谨防HK尝试恶意注入 提现");
        }


        int result1 = workUserInfo.getAccountmoney().compareTo(transMoneyInfo.getTransmoney());
        if (result1 == -1) {
            log.error("资金安全日志: 提现金额大于账户余额");
            return R.fail("资金安全日志: 账户余额小于提现金额");
        }


        BigDecimal bigDecimalBy1 = new BigDecimal(1.00);
        int bigDecimalBy1Res = transMoneyInfo.getTransmoney().compareTo(bigDecimalBy1);
        if (bigDecimalBy1Res == -1) {
            log.error("资金安全日志: 提现金额小于1");
            return R.fail("资金安全日志: 提现金额不能小于1元");
        }

        BigDecimal bigDecimalBy5000 = new BigDecimal(5000.00);
        int bigDecimalBy5000Res = transMoneyInfo.getTransmoney().compareTo(bigDecimalBy5000);
        if (bigDecimalBy5000Res == 1) {
            log.error("资金安全日志: 提现金额不能大于5000");
            return R.fail("资金安全日志: 提现金额不能大于5000");
        }


        String ip = IpKit.getRealIp(getRequest());
        if (StrKit.isBlank(ip)) {
            ip = "127.0.0.1";
        }
        Map<String, String> params = TransferModel.builder()
                .mch_appid(WxPayConfig.appId)
                .mchid(WxPayConfig.mchId)
                .nonce_str(WxPayKit.generateStr())
                .partner_trade_no(WxPayKit.generateStr())
                .openid(workUserInfo.getWxopenid())
                .check_name("NO_CHECK")
                .amount(MoneyUtil.correctYuanToFen(transMoneyInfo.getTransmoney()) + "")
                .desc(transMoneyInfo.getSqrusername() + "提现")
                .spbill_create_ip(ip)
                .build()
                .createSign(WxPayConfig.partnerKey, SignType.MD5, false);

        InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("apiclient_cert.p12");
        String transfers = WxPayApi.transfers(params, resourceAsStream, WxPayConfig.mchId);


        Map<String, String> map = WxPayKit.xmlToMap(transfers);
        String returnCode = map.get("return_code");
        String resultCode = map.get("result_code");
        log.info("====返回信息:" + JSON.toJSONString(map));
        log.info("[微信付款到零钱]返回信息报文:" + JSON.toJSONString(map));
        if (WxPayKit.codeIsOk(returnCode) && WxPayKit.codeIsOk(resultCode)) {
            MoneyDetail moneyDetail = new MoneyDetail();
            moneyDetail.setId(IdWorker.getId());
            moneyDetail.setUserid(workUserInfo.getId() + "");
            moneyDetail.setOrderid(transMoneyInfo.getId() + "");
            moneyDetail.setFkfserid(adminUserInfo.getId() + "");
            moneyDetail.setFkfname(adminUserInfo.getName());
            moneyDetail.setFkfphone(adminUserInfo.getPhone());
            moneyDetail.setTrademoney(transMoneyInfo.getTransmoney());
            moneyDetail.setMoneymark("[工人提现]");
            moneyDetail.setSkfuserid(transMoneyInfo.getSqruserid());
            moneyDetail.setSkfusername(transMoneyInfo.getSqrusername());
            moneyDetail.setSkfuserphone(transMoneyInfo.getSqruserphone());
            moneyDetail.setBefmoeny(workUserInfo.getAccountmoney());
            moneyDetail.setAftmoney(DecimalUtil.subtract(workUserInfo.getAccountmoney(), transMoneyInfo.getTransmoney()));
            moneyDetail.setMoneytype("3");
            moneyDetail.setCtime(new Date());
            moneyDetailService.save(moneyDetail);

            transMoneyInfo.setApplystatus("2");
            transMoneyInfo.setTransbz(JSON.toJSONString(map));
            transMoneyInfo.setShuserid(adminUserInfo.getId() + "");
            transMoneyInfo.setShusername(adminUserInfo.getName());
            transMoneyInfo.setShdate(new Date());
            transMoneyInfo.setMerchantno(WxPayConfig.mchId);
            transMoneyService.updateById(transMoneyInfo);

            workUserInfo.setAccountmoney(DecimalUtil.subtract(workUserInfo.getAccountmoney(), transMoneyInfo.getTransmoney()));
            userService.updateById(workUserInfo);
            return R.success("提现成功");
        } else {
            transMoneyInfo.setTransbz(JSON.toJSONString(map));
            transMoneyService.updateById(transMoneyInfo);
            log.error("资金安全日志: 提现失败" + JSON.toJSONString(map));
            return R.fail("提现失败" + JSON.toJSONString(map));
        }

    }


}
